pub mod audio_device;
pub mod audio_manager;
pub mod audio_stream;
pub mod call_history;
pub mod call_manager;
mod commands;
pub mod config_manager;
pub mod sip_manager;

#[cfg(test)]
mod auth_tests {
    use crate::sip_manager::{SipConfig, SipManager, TransportType, RegistrationStatus};
    use std::time::Duration;
    use tokio::time::timeout;

    #[tokio::test]
    async fn test_config_validation() {
        let sip_manager = SipManager::new();
        
        // Test empty server
        let invalid_config = SipConfig {
            server: "".to_string(),
            port: 5060,
            username: "test".to_string(),
            password: "test".to_string(),
            transport: TransportType::UDP,
            display_name: None,
            local_port: None,
        };
        
        let result = sip_manager.login(invalid_config).await;
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("Server address cannot be empty"));
        
        // Test empty username
        let invalid_config = SipConfig {
            server: "test.server.com".to_string(),
            port: 5060,
            username: "".to_string(),
            password: "test".to_string(),
            transport: TransportType::UDP,
            display_name: None,
            local_port: None,
        };
        
        let result = sip_manager.login(invalid_config).await;
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("Username cannot be empty"));
        
        // Test empty password
        let invalid_config = SipConfig {
            server: "test.server.com".to_string(),
            port: 5060,
            username: "test".to_string(),
            password: "".to_string(),
            transport: TransportType::UDP,
            display_name: None,
            local_port: None,
        };
        
        let result = sip_manager.login(invalid_config).await;
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("Password cannot be empty"));
        
        // Test invalid port
        let invalid_config = SipConfig {
            server: "test.server.com".to_string(),
            port: 0,
            username: "test".to_string(),
            password: "test".to_string(),
            transport: TransportType::UDP,
            display_name: None,
            local_port: None,
        };
        
        let result = sip_manager.login(invalid_config).await;
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("Invalid port number"));
    }

    #[tokio::test]
    async fn test_registration_status_flow() {
        let sip_manager = SipManager::new();
        
        // Initial status should be Unregistered
        let status = sip_manager.get_registration_status().await;
        assert_eq!(status, RegistrationStatus::Unregistered);
        
        // Test logout when not logged in
        let result = sip_manager.logout().await;
        assert!(result.is_ok());
        
        let status = sip_manager.get_registration_status().await;
        assert_eq!(status, RegistrationStatus::Unregistered);
    }

    #[tokio::test]
    async fn test_retry_mechanism() {
        let sip_manager = SipManager::new();
        
        // Initial retry count should be 0
        let retry_count = sip_manager.get_retry_count().await;
        assert_eq!(retry_count, 0);
        
        // Max retries should be configured
        let max_retries = sip_manager.get_max_retries();
        assert!(max_retries > 0);
        
        // Auth failure count should be 0 initially
        let auth_failures = sip_manager.get_auth_failure_count().await;
        assert_eq!(auth_failures, 0);
        
        // Should not be authentication locked initially
        let is_locked = sip_manager.is_authentication_locked().await;
        assert!(!is_locked);
        
        // Max auth failures should be configured
        let max_auth_failures = sip_manager.get_max_auth_failures();
        assert!(max_auth_failures > 0);
    }

    #[tokio::test]
    async fn test_connection_test() {
        let sip_manager = SipManager::new();
        
        // Test connection to invalid server (should fail gracefully)
        let result = timeout(
            Duration::from_secs(5),
            sip_manager.test_connection(
                "invalid.server.test".to_string(),
                5060,
                TransportType::UDP
            )
        ).await;
        
        // Should complete within timeout (not hang)
        assert!(result.is_ok());
        
        let connection_result = result.unwrap();
        assert!(connection_result.is_ok());
        
        let test_result = connection_result.unwrap();
        // Connection to invalid server should fail
        assert!(!test_result.success);
        assert!(test_result.error_message.is_some());
    }

    #[tokio::test]
    async fn test_network_status() {
        let sip_manager = SipManager::new();
        
        let network_status = sip_manager.get_network_status().await;
        
        // Initially should not be connected
        assert!(!network_status.is_connected);
        assert!(network_status.active_transport.is_none());
        assert!(network_status.local_address.is_none());
        assert!(network_status.server_address.is_none());
    }

    #[tokio::test]
    async fn test_auth_failure_reset() {
        let sip_manager = SipManager::new();
        
        // Reset auth failures
        sip_manager.reset_auth_failures().await;
        
        // Should be 0 after reset
        let auth_failures = sip_manager.get_auth_failure_count().await;
        assert_eq!(auth_failures, 0);
        
        // Should not be locked after reset
        let is_locked = sip_manager.is_authentication_locked().await;
        assert!(!is_locked);
    }

    #[tokio::test]
    async fn test_last_error_tracking() {
        let sip_manager = SipManager::new();
        
        // Initially should have no error
        let last_error = sip_manager.get_last_error().await;
        assert!(last_error.is_none());
    }
}

use audio_manager::AudioManager;
use call_history::CallHistoryManager;
use call_manager::CallManager;
use commands::AppState;
use config_manager::ConfigManager;
use sip_manager::SipManager;
use std::sync::Arc;

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    // Initialize logging (using Tauri's built-in logging)

    // Create managers
    let sip_manager = Arc::new(SipManager::new());
    let call_manager = Arc::new(CallManager::new());
    let audio_manager = Arc::new(AudioManager::new().expect("Failed to initialize audio manager"));
    let config_manager = Arc::new(ConfigManager::new().expect("Failed to initialize config manager"));
    
    // Initialize call history database
    let app_data_dir = dirs::data_dir()
        .unwrap_or_else(|| std::env::current_dir().unwrap())
        .join("tauri-sip-client");
    std::fs::create_dir_all(&app_data_dir).expect("Failed to create app data directory");
    let db_path = app_data_dir.join("call_history.db");
    let call_history_manager = Arc::new(CallHistoryManager::new(db_path).expect("Failed to initialize call history manager"));

    // Create app state
    let app_state = AppState {
        sip_manager,
        call_manager,
        audio_manager,
        config_manager,
        call_history_manager,
    };

    let sip_manager_for_setup = app_state.sip_manager.clone();
    let call_manager_for_setup = app_state.call_manager.clone();
    let call_history_manager_for_setup = app_state.call_history_manager.clone();

    tauri::Builder::default()
        .plugin(tauri_plugin_opener::init())
        .manage(app_state)
        .setup(move |app| {
            // Set app handle in managers for event emission
            let handle = app.handle().clone();
            let handle_clone = handle.clone();
            tauri::async_runtime::spawn(async move {
                sip_manager_for_setup.set_app_handle(handle).await;
                call_manager_for_setup.set_app_handle(handle_clone).await;
                call_manager_for_setup.set_call_history_manager(call_history_manager_for_setup).await;
            });
            Ok(())
        })
        .invoke_handler(tauri::generate_handler![
            commands::login,
            commands::logout,
            commands::get_registration_status,
            commands::test_connection,
            commands::get_network_status,
            commands::get_retry_count,
            commands::get_max_retries,
            commands::force_retry_registration,
            commands::get_last_error,
            commands::get_auth_failure_count,
            commands::get_max_auth_failures,
            commands::reset_auth_failures,
            commands::is_authentication_locked,
            commands::make_call,
            commands::answer_call,
            commands::reject_call,
            commands::hangup_call,
            commands::mute_call,
            commands::get_active_calls,
            commands::get_call_info,
            commands::simulate_incoming_call,
            commands::cancel_incoming_call_timeout,
            commands::handle_remote_hangup,
            commands::get_call_quality_metrics_from_call_manager,
            commands::get_audio_devices,
            commands::set_audio_device,
            commands::get_audio_levels,
            commands::get_detailed_audio_devices,
            commands::set_audio_stream_config,
            commands::get_audio_stream_config,
            commands::update_audio_levels,
            commands::create_audio_stream_with_quality,
            commands::set_stream_quality_settings,
            commands::get_stream_quality_settings,
            commands::process_incoming_rtp,
            commands::get_outgoing_rtp,
            commands::get_active_audio_streams,
            commands::load_config,
            commands::save_config,
            commands::export_config,
            commands::import_config,
            commands::config_exists,
            commands::get_call_history,
            commands::clear_call_history,
            commands::get_call_count,
            commands::delete_call_record,
            commands::get_recent_numbers,
            commands::make_call_from_history,
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
